package dtm

import (
	"context"
	"database/sql"
	// "fmt"
	"time"

	"mall/common/globalkey"
	"mall/common/resultx"
	"mall/service/backend/common/i18n"
	"mall/service/promotion/model"
	"mall/service/promotion/rpc/internal/svc"
	"mall/service/promotion/rpc/types/promotion"

	"github.com/dtm-labs/client/dtmgrpc"
	// "github.com/sirupsen/logrus"
	"github.com/volatiletech/null/v8"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/zeromicro/go-zero/core/logx"
)

type UpdatePromotionLogRevertLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdatePromotionLogRevertLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePromotionLogRevertLogic {
	return &UpdatePromotionLogRevertLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *UpdatePromotionLogRevertLogic) UpdatePromotionLogRevert(in *promotion.UpdatePromotionLogReq) (*promotion.BaseResp, error) {
	// logrus.Info(fmt.Sprintf("UpdatePromotionLogRevert UpdatePromotionLogReq: %+v", in))

	if in.UserId == nil || *in.UserId == 0 {
		return nil, resultx.StatusError(resultx.USER_ID_REQUIRED, "")
	}

	if in.OrderId == nil || *in.OrderId == 0 {
		return nil, resultx.StatusError(resultx.ORDER_ID_REQUIRED, "")
	}

	if in.StatusRevert == nil || *in.StatusRevert == 0 {
		return nil, resultx.StatusError(resultx.PROMOTION_STATUS_INVALID, "")
	}

	if len(in.Logs) == 0 {
		return &promotion.BaseResp{}, nil
	}

	// 获取子事务屏障对象
	barrier, err := dtmgrpc.BarrierFromGrpc(l.ctx)
	if err != nil {
		return nil, resultx.StatusError(resultx.DTM_ERROR, err.Error())
	}

	// 开启子事务屏障
	err = barrier.CallWithDB(l.svcCtx.DB, func(tx *sql.Tx) error {
		status := int32(*in.StatusRevert)
		now := time.Now()
		usedAt := null.TimeFrom(now)

		for _, v := range in.Logs {
			if v.CouponId != nil && *v.CouponId > 0 {
				coupon, err := l.svcCtx.Coupon.FindOneNoCache(l.ctx, tx, *v.CouponId)
				if err != nil {
					if err == sql.ErrNoRows {
						continue
					}

					return err
				}

				var orderId uint64
				if status == globalkey.StatusUsed {
					coupon.UsedAt = usedAt
					orderId = *in.OrderId
				} else if status == globalkey.StatusStarted {
					coupon.UsedAt = null.TimeFromPtr(nil)
				}

				coupon.OrderID = orderId
				coupon.Status = uint16(status)
				err = l.svcCtx.Coupon.Update(l.ctx, tx, coupon)
				if err != nil {
					return err
				}

				var mods []qm.QueryMod
				mods = append(mods, model.PromotionCouponOprLogWhere.CouponID.EQ(*v.CouponId))
				mods = append(mods, model.PromotionCouponOprLogWhere.UserID.EQ(*in.UserId))
				mods = append(mods, model.PromotionCouponOprLogWhere.Status.EQ(uint16(globalkey.StatusEnabled)))
				mods = append(mods, qm.OrderBy(model.PromotionCouponOprLogColumns.LogID+" DESC"))
				mods = append(mods, qm.Limit(int(1)))
				_, err = model.PromotionCouponOprLogs(mods...).UpdateAll(l.ctx, tx, model.M{
					model.PromotionCouponOprLogColumns.Status: uint8(globalkey.StatusExpired),
				})
				if err != nil {
					logx.Errorw("UpdatePromotionLogRaw PromotionCouponOprLog Update err", logx.Field("detail", err.Error()))
				}
			} else if v.ActivityId != nil && *v.ActivityId > 0 {
				var mods []qm.QueryMod
				mods = append(mods, model.PromotionActivityLogWhere.ActivityID.EQ(*v.ActivityId))
				mods = append(mods, model.PromotionActivityLogWhere.UserID.EQ(*in.UserId))
				mods = append(mods, model.PromotionActivityLogWhere.OrderID.EQ(*in.OrderId))
				mods = append(mods, model.PromotionActivityLogWhere.Status.EQ(uint8(globalkey.StatusEnabled)))
				mods = append(mods, qm.OrderBy(model.PromotionActivityLogColumns.LogID+" DESC"))
				mods = append(mods, qm.Limit(int(1)))
				_, err = model.PromotionActivityLogs(mods...).UpdateAll(l.ctx, tx, model.M{
					model.PromotionActivityLogColumns.Status: uint8(globalkey.StatusExpired),
				})
				if err != nil {
					logx.Errorw("UpdatePromotionLogRaw PromotionActivityLog Update err", logx.Field("detail", err.Error()))
				}
			}
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return &promotion.BaseResp{
		Msg: i18n.UpdateSuccess,
	}, nil
}
